/*
** SMSE2K CPU Interface, take 2
**
** A few words about the CPU interface...
** - CPUs in SMSE2K don't do a lot of calls to common code except for accessing an MMU.
** - Scheduling is not done in the CPU cores. This is done in the hardware class, which
**   controls CPU/timer scheduling and audio rendering.
** - When the interface v
*/

#pragma once
#ifndef __CPU_H
#define __CPU_H

// Interface version. If we change the CPU interface at any time, we change this version number
// so the factories don't flip out on us. However, you will need to change stuff:
//
// 
#define CPU_INTERFACE_CURRENT_VERSION   1


// This is always the current version of the CPU interface. Older versions are implemented through CLegacyCPU.
// We never implement this directly. This needs to be initialized through CBaseCPU, no matter how little it actually implements...
class ICpu {
	public: 
		virtual int  Init(int clock) = 0; // Initialize the CPU
		virtual int  GetClock() = 0;
		virtual void  AssignMMU(int slot, CBaseMMU* mmu)   = 0; // Assign a MMU to the CPU
		virtual int  Exec(int cycles)								= 0; // Run the CPU
		virtual int  Burn(int cycles) = 0;

		virtual void SetRegister(const char* regname, UINT64 val) = 0;

		virtual int  GetInterruptStatus(int line) = 0;
		virtual void Interrupt(int line, int state) = 0; // Interrupts the CPU. The IRQ will remain until it is acknowledged by the CPU.
		virtual void Interrupt(int line, int state, int vector) = 0; // Interrupts but with a vector (not required to implement)
		virtual void Shutdown()										= 0; // Begins freeing memory
		virtual void Reset() = 0;
};



// CBaseCPU, implementing the current CPU version. A lot of stuff in ICpu has to be implemented by the cores,
// this class implements the optional calls.
class CBaseCPU : public ICpu {
		protected:
			int clock;

		public:
				virtual int  Burn(int cycles)     { return 0; }
				virtual int  GetClock() { return this->clock; }
				virtual void  Shutdown() { };
				virtual int  GetInterruptStatus(int) { return 0; }
				virtual void SetRegister(const char* regname, UINT64 val) { };
				virtual void Interrupt(int line, int state) = 0; // Still needs to be implemented
				virtual void Interrupt(int line, int state, int vector)  { this->Interrupt(line,state); }
};

// CPU_CLASS: Define this in your CPU core when declaring your class. This helps with portability.
#define CPU_CLASS(x) class x : public CBaseCPU

// LEGACY_CPU_CLASS: Replace CPU_CLASS with this when the CPU interface has changed.
#define LEGACY_CPU_CLASS(name, version) class x : public CBaseCPUVersion##version

#endif